home *** CD-ROM | disk | FTP | other *** search
- page ,132
- Title * HD * - Hard Disk Seek and Read, Test Program
- Subttl Written, Directed, and Copyrighted by R. Steincross Feb 1985
-
- Comment ~ This program honors several slash commands as shown below to determine the
- performance of a hard disk drive or controller. Normally, only the first slash
- command encountered is executed. If a "/2" is detected on the command line, then
- all testing is directed to the second drive of the controller. If no params are
- entered, then the help screen is displayed. (commands listed in search priority)
-
- /2 Use the second drive instead of the first.
- /I Information about the drive(s) is reported.
- /S n Seek test from 0 to 'n' and Recal from 'n' to 0.
- /R n Read 'n' Tracks and report the time taken.
- /P Park the drive on the last track.
- /? Help screen displayed. (also, if no parameter specified)
- ~
- cr equ 0Dh
- lf equ 0Ah
- eof equ "$" ;used to terminate strings going to CRT
- bell equ 07
- DOS equ 21h ;this is the function interrupt into DOS
- DISK equ 13h ;this is the interrupt to the Disk BIOS
-
- code_seg segment ;begin code segment
- assume cs:code_seg, ds:code_seg
-
- org 080h ;this picks up the command line
- cmd_len db ?
- cmd_line db ?
-
- org 100h ;COM files org at 100h
- HD proc near
- entry: jmp go
-
- drive_sel db 80h ;this is drive 1, make 81 for drive 2
- db "******" ;this is the ASCII buffer for numeric output,
- ascii db "*",eof ;label points to rightmost position in buffer
- number dw 0000 ;written to by GET_Num
- cs_save dw 0000 ;keep a copy of our Code Segment
- leading0 db '0' ;used in Time_Display routine
-
- ; The following fields are set when determined by GET_Params:
- num_drives db 00 ; 1..D
- num_tracks dw 0000 ; 0..T gets altered by get_param
- num_heads db 00 ; 0..H-1
- num_sectors db 00 ; 1..S
-
- ; These storage locations are used by Time_Start, _Stop, & _Display
- num_minutes db 00 ; 0..59 minutes
- num_seconds db 00 ; 0..59 seconds, used in the get_time routines
- num_100ths db 00 ; 0..99, this is 100th of a second
- ; num_time dw 0000 ; 0..32000, represents 32seconds, in 1/100ths
-
- db 25 dup (' Stack .')
- stack dw 1111h
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- org 200h ;this keeps the code in a constant place for testing
-
- go:
- mov sp,offset stack
- push cs ;This is a Must!
- mov ax,cs
- mov ds,ax ;all segment registers are AT the Code Segment on start-up
- mov es,ax
- mov CS_Save,AX ;used when we exit this program
- sti ;enable interrupts
- mov dx,offset sign_on ;Show the sign-on message
- call crt
- call upper ;convert command line to all UPPER case
-
- ; * * * Second Drive Selection * * *
- mov ah,"2"
- call find ;see if this is on the command line
- jne check_F ;NO, go on to next check
- inc drive_sel ;select next drive
- mov dx,offset msg_2nd
- call crt
-
- check_F: ; * * * FLOPPY Drive Selection * * *
- mov ah,"F"
- call find
- jne check_I
- mov al,drive_sel
- and al,00000001b ;mask off the high (hard disc) bit
- mov drive_sel,al
- mov dx,offset msg_floppy
- call crt
-
- check_I: ; * * * INFOrmation Report * * *
- ;we now know whether to use drive 1 or 2, so...
- call GET_Params ;get the parameters for selected drive
- mov ah,"I"
- call find
- jne check_S ;go on to next test
- call INFO ;report the Facts to user
-
- check_S: ; * * * SEEK 'n' Tracks * * *
- mov ah,"S"
- call find
- jne check_R
- call get_num ;get the number of tracks to seek
- je chk_s ;number was found, do something
- mov dx,offset msg_missing
- call crt
- jmp short check_R ;abandon the SEEK routine unless param found
- chk_s: call SEEK ;do the Seek test
-
- check_R: ; * * * READ 'n' Tracks * * *
- mov ah,"R"
- call find
- jne check_P
- call get_num ;get the number of tracks to seek
- je chk_r ;number was found, do something
- mov dx,offset msg_missing
- call crt
- jmp short check_P ;abandon the READ routine unless param found
- chk_r: call READ ;do the Read test
-
- check_P: ; * * * PARK the Selected Drive * * *
- mov ah,"P"
- call find
- jne check_Q
- call PARK
-
- check_Q: ; * * * Look for QUESTION Mark * * *
- mov ah,"?"
- call find
- jne done
- call HELP
- done:
- mov dx,offset msg_blank
- call crt ;clear any pending error msgs
- mov dx,offset msg_stack ;get ready to squeal of bad stack
- mov cx,cs_save
- pop ax ;get CS from stack
- cmp ax,cx ;better be equal, or else stack is messed up
- je exit
- call crt
- exit: int 20h ;back to DOS
-
- ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
- ;
- ; END of Top Level Program
- ;
- ; MAIN Routines Follow
- ;
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * * * INFOrmation Report * * *
- INFO:
- call show_params
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * * * Found QUESTION Mark * * *
- HELP:
- mov dx,offset msg_help
- call crt
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * * * SEEK 'n' Tracks * * *
- SEEK:
- call RECAL
- call Time_Start
- mov ax,number
- dec ax ;AX has number of tracks, make last tk #
- call Load_Cyl
- mov dh,num_heads ;restore DH-max head number
- mov dl,drive_sel ;DL=drive number, 80 or 81
- mov ah,0Ch
- int DISK ;seek specified track
- jnc seek_1
- jmp bad_disk
- seek_1:
- nop
- nop
- nop
- mov ah,10h ;wait while busy
- int DISK
- jc seek_1
-
- call Time_Stop
- mov dx,offset msg_seektime
- call crt
- call Time_Display
- call Time_Start
- call RECAL
- call Time_Stop
- mov dx,offset msg_recaltime
- call crt
- call Time_Display
- call crlf
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * * * READ 'n' Tracks * * *
- READ:
- call RECAL
-
- mov ax,offset Buffer ;find the end of this pgm
- shr ax,1 ;put it into SEGMENT format
- shr ax,1 ;put it into SEGMENT format
- shr ax,1 ;put it into SEGMENT format
- shr ax,1 ;put it into SEGMENT format
- add ax,cs_save ;find out where we are located
- add ax,1000h ;flip up to the next segment
- and ax,0F000h ;mask off all but next 64k boundary
- mov es,ax ;now we have 64k for DMA from disk
-
- call Time_Start
- mov cx,number ;get the number of tracks requested
- cmp cx,0000 ;
- je read_loop
- dec cx ;AX has number of tracks, make last tk #
-
- read_loop:
- push cx ;save 'how many times' we want to do this
- mov ax,cx
- call Load_Cyl ;* * * make sure this sets sector #1
- mov dh,00 ;starting head number
- mov al,num_heads ;get head number
- mul num_sectors ;calculate: AL = HEADS * SECTORS = 55h (85d)
- mov dl,drive_sel ;DL=drive number, 80 or 81
- mov bx,000 ;we have 64k to DMA into
- mov ah,02
- int DISK ;read the disc
- pop cx ;recover the count of 'tracks to do'
- jnc read_1
- jmp bad_disk
- read_1:
- mov ah,10h ;wait while busy
- int DISK
- jc read_1
- loop read_loop ;do it 'till they're all read...
-
- call Time_Stop
- mov dx,offset msg_numtracks
- call crt
- mov ax,number ;get the number of tracks seeked
- call ax2dec
- call crt
- mov dx,offset msg_readtime
- call crt
- call Time_Display
- call crlf
- RET
-
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; * * * PARK the Selected Drive * * *
- PARK:
- mov dx,offset msg_recal
- call crt
- call RECAL
- mov dx,offset msg_seek
- call crt
- mov dh,num_heads ;restore DH-max head number
- mov dl,drive_sel ;DL=drive number, 80 or 81
- mov ax,num_tracks
- call Load_Cyl ;put cylinder number into CX from AX
- mov ah,0Ch ; SEEK
- int DISK
- jnc park4
- jmp bad_disk
-
- park4:
- mov dx,offset msg_parked
- call crt
- mov ax,num_tracks
- call ax2dec ;put on CRT the track we parked at
- call crt
- call crlf ;... and leave message on CRT
- RET
-
-
- ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
- ;
- ; END of Main Routines
- ;
- ; SUBROUTINES and UTILITIES Follow
- ;
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; These routines manage the TIMER function.
- ; They start, stop, and display the elapsed time of some disk action.
-
- Time_Start:
- push ax
- push bx
- push cx
- push dx
- mov ah,2Ch ;get the time
- int DOS ;CH=hrs, CL=min, DH=sec, DL=1/100sec
- mov dx,0001 ;clear the seconds, the hundredths,
- mov cl,00 ;...and the minutes
- mov ah,2Dh ;send time to system
- int DOS ;and reset the system timer
- pop dx
- pop cx
- pop bx
- pop ax
- Ret
-
- Time_Stop:
- push ax
- push bx
- push cx
- push dx
- mov ah,2Ch ;get the time
- int DOS ;CH=hrs, CL=min, DH=sec, DL=1/100sec
- mov num_seconds,DH
- mov num_100ths,DL
- mov num_minutes,CL
- ; mov ax,100 ; Seconds times 100...
- ; mul num_seconds ; are now in AX. This is good to 32 sec
- ; mov dh,00
- ; add ax,dx ;add in the 100ths of a second for a max of 32000 100ths
- ; mov num_time,ax ;and save for later use
- pop dx
- pop cx
- pop bx
- pop ax
- Ret
-
- Time_Display:
- push ax
- push bx
- push cx
- push dx
- push si
- mov al,num_minutes
- cmp al,0 ;don't say MINUTES, if there aren't any
- je no_mins
- call al2dec
- call crt
- mov dx,offset msg_min
- call crt
- no_mins:
- mov al,num_seconds
- call al2dec ;say how many seconds
- call crt
- mov dx,offset msg_sec
- call crt
- mov al,num_100ths
- call al2dec ;say how many 100ths
- cmp al,1 ;were there more than 1 digits?
- jg sec_ok ;yes, no problem
- dec dx ;point previous char position
- mov si,dx
- mov al,leading0
- mov [si],al ;write the leading zero
- sec_ok:
- call crt
- mov dx,offset msg_100ths
- call crt
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- Ret
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Suck the heads out to track zero on the selected drive
- Recal:
- mov dl,drive_sel ;80 selects first hard disk, 81 the second
- xor cx,cx ; * * * should this be: XOR CX,CX ?
- mov ah,11h ;... recal hard disk
- int DISK
- jnc recal_wait
- jmp bad_disk
-
- recal_wait:
- nop
- nop
- nop
- mov ah,10h ;wait while busy
- int DISK
- jc recal_wait
- RET
-
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Load the Cylinder number into the CX registers for seek
- ; Enter with the binary track number in the AX.
-
- Load_Cyl:
- mov ch,al ;put back LSBits
- ror ah,1
- ror ah,1 ;rotate MSBits into alignment
- or ax,0100h ;sector # = 1
- mov cl,ah ;put back MSBits
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Convert the AL register to a Decimal number in the ASCII buffer
- AL2Dec:
- mov ah,00 ;clear hi byte to use AX2DEC routine
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Convert the AX register to a Decimal number and put it in the ASCII buffer.
- ; AL returns the length of the ASCII number, DX points to the ASCII string.
- ; The value should probably be less than 32000 for this code to work.
- AX2Dec:
- push cx
- push bx
- push si
- mov si,offset ascii ;last char position in buffer
- mov cl,01 ;ASCII character count
- mov bx,10 ;decimal divide
- ax2dec_loop:
- xor dx,dx ;this is where we put the remainder
- div bx ;divide by 10
- or dl,30h ;convert to ASCII
- mov [si],DL ;save digits from right to left
- cmp ax,0000 ;have we anything to divide, still?
- je ax_done ;quit if there is nothing left
- dec si ;point to previous location in string for next digit
- inc cl ;keep track of number of ASCII characters
- jmp ax2dec_loop
- ax_done: ;leading zeros are supressed
- mov dx,si ; keeps from showing leading spaces
- mov al,cl ;recover the number of ASCII chars generated
- pop si
- pop bx
- pop cx
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Disk controller got an error, leave existing message on CRT.
- ; Give BAD message, then controller error number to help debug the problem.
-
- Bad_Disk:
- mov dx,offset bad_msg
- call crt
- mov dl,drive_sel
- mov ah,01 ;get controller status
- int DISK
- ; mov al,ah ;error code may be in AL
- xor ah,ah
- call al2dec
- call crt
- call crlf
- ret
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Get the Parameters of the chosen drive. They are required
- ; for SHOW_PARAMS, and all routines which seek, park or read
- ; the drive.
-
- GET_Params:
- mov dx,offset msg_notready
- call crt ;put up the NOT READY msg in case we aren't
- xor cx,cx
- mov dh,ch
- mov dl,drive_sel ;80 selects first hard disk, 81 the second
- mov ah,10h ;check if drive is ready
- int DISK
- jnc get1 ; is ready, so...
- jmp bad_disk
- get1:
- mov ah,08h ;get drive params
- int DISK
- jnc get3
- jmp bad_disk
- get3:
- push dx ;clear the error message from the screen
- mov dx,offset msg_blank
- call crt
- pop dx ;restore DH - max head number, and DL - number of drives
- mov ah,cl ;get MSBits
- rol ah,1 ;only left two bits are used
- rol ah,1 ;rotate MSBits into alignment (right 2 bit locations)
- and ax,0300h ;mask all but MSBits
- mov al,ch ;get LSBits AX now has # of tracks
- inc ax ;correct the count to last (diag) track
- mov num_tracks,ax ;save number of tracks
- mov num_heads,dh ;save number of heads 0..n-1
- and cl,00111111b ;mask out hi bits of track 0..t
- mov num_sectors,cl ;save number of sectors 1..s (?)
- mov num_drives,dl ;save number of drives 1..2
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Put the following parameters on the display:
- ; Selected drive, Total Number of drives, number of Tracks,
- ; number of Heads, number of Sectors.
-
- SHOW_Params:
- mov dx,offset msg_drives
- call crt ;how many drives detected
- mov al,num_drives
- and al,00000111b
- call al2dec ;send AL to CRT in decimal
- call crt
- mov dx,offset msg_sel
- call crt ;which drive was selected
- mov al,drive_sel
- and al,01h
- inc al ; 0 = 1st, 1 = 2nd drive
- call al2dec
- call crt
- mov dx,offset msg_tracks
- call crt ;number of tracks this drive
- mov ax,num_tracks ; already adjusted for diag cyl
- inc ax ;is 0..n-1, s/b 1..n
- call ax2dec ;send AX to CRT in decimal
- call crt
- mov dx,offset msg_heads
- call crt ;number of heads this drive
- mov al,num_heads
- inc al ; 1 = 2hds, 3 = 4hds, 4 = 5hds, etc.
- call al2dec
- call crt
- mov dx,offset msg_sectors
- call crt
- mov al,num_sectors
- call al2dec
- call crt
- call crlf
- ret
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; point the DX to your favorite message, then call here for output on CRT
- CRT:
- mov ah,09 ; AX gets wasted
- int DOS
- ret
-
- crt_crlf:
- call crt
- crlf: mov dx,offset msg_crlf
- call crt
- ret
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Enter with char in AH to compare against the command line.
- ; Return with Zero Flag set if found and SI pointing past the char.
- ; Return Zero Flag clear if not found anywhere on command line.
- ; All other registers are preserved except SI, CX and flags.
- ; On return, SI points at char if match was made.
- ; The command line is found at CS:81, the length of the line
- ; is at CS:80. Located at length plus 81 is a Carriage Return
- ; which terminates the line. All chars have been made UPper case.
- FIND:
- cld ;we want to search forward
- mov si,offset cmd_line ;always scan the entire cmd line
- mov ch,00
- mov cl,[cmd_len] ;get the length
- cmp ch,cl
- je no_find ;was of zero length, flag no compare
-
- find_slash:
- lodsb ;get ax,[si] and increment si
- cmp al,"/" ;scan fwd 'till we find one
- loopne find_slash ;loop here if not at end of line and not eq /
- cmp cl,ch ;are we at zero, yet?
- je no_find
- lodsb ;get char following slash (/)
- cmp ah,al
- je return ;this is it! return with
- loop find_slash ;try looking at next one
- no_find:
- cmp ah,0FFh ;set the NO-COMPARE flag
- return:
- ret
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Gets a number which may follow a slash-letter parameter.
- ; On entry, SI points past the matched letter in the command line.
- ; CX should still have count to go to end of line.
- ; Output is stored in memory at word NUMBER for use by other routines.
- ; If no number is detected, zero is written into NUMBER and NE=true
- ; All leading characters except slash (/) are skipped till number is
- ; found. Then number is converted to binary till non-number is found.
-
- GET_Num:
- cmp ch,cl ;bail out if no more chars on cmd line
- je no_val
- mov dx,0000
- mov number,dx ;clear the accumulator
- pre_scan: ;throw away all except / till we get a number
- mov al,[si] ;get the next char
- cmp al,'/' ;bail out if into next command
- je no_val
- cmp al,'0' ;above an ascii 0 ?
- jae get_dig ; yes
- cmp al,'9' ;below an ascii 9 ?
- jbe get_dig ; yes
- inc si ;point to next char
- loop pre_scan ;no, look at next char if there are more
- jmp short no_val ;end of cmd line, bail out
- get_dig:
- and ax,000Fh ;convert ASCII to 0 < nibble < 10
- mov bx,ax ;save the number for later
- mov al,10 ;prepare to multiply
- mul number ; AH is zero, AX gets the result ( < 64k )
- add ax,bx ;add in previous value
- mov number,ax
- inc si
- mov al,[si]
- cmp al,'0'
- jb get_done
- cmp al,'9'
- ja get_done
- jmp short get_dig
- get_done:
- mov al,0
- get_out:
- cmp al,0
- RET
-
- no_val:
- mov al,0FFh
- jmp get_out
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Convert the entire command line to UPPER case characters
- ; Registers are trashed as may be convenient.
- UPper:
- mov si,offset cmd_line ;point to first char of Command line
- mov ch,00
- mov cl,[cmd_len] ;get the length of the line
- cmp ch,cl ;is the length = zero?
- je up_done ;yes, bail out
- up_shift:
- ; lodsb ;cmd_line ;can't allow SI to get incremented
- mov al,[si] ;get a char
- cmp al,'a' ;is it lower case?
- jb up_case ;no
- cmp al,'z'
- ja up_case ;no
- and al,0DFh ;yes, make it upper
- mov [si],al ;and write it back into place
- up_case:
- inc si ;point next char
- loop up_shift ;decrement the CX counter, and keep on strokin'
- up_done:
- mov al,'/'
- mov [si],al ;mark the end of the string
- RET
-
- ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ; Temporary routine to indicate that some Top Level
- ; programs above have not been completed.
-
- not_done:
- mov dx,offset msg_notdone
- call crt
- Ret
-
- msg_notdone db cr,lf,"The selected function has not yet been implemented.",cr,lf,eof
-
- sign_on db "HD - a Hard Disk Test Program. Copyright 1985 by R. Steincross. Vers 0.2 ",cr,lf,eof
- msg_notready db "Disk Drive Not Ready. ",cr,eof
- msg_parm db "Couldn't get Drive Parameters. ",cr,eof
- msg_blank db " ",cr,eof
- msg_2nd db "The SECOND Disc Drive has been selected. ",cr,lf,eof
- msg_recal db "Slow Seek to Track Zero. ",cr,eof
- msg_seek db "Fast Seeking to Final Track. ",cr,eof
- msg_parked db "The drive has been sent to the last (diagnostic) cylinder, track number ",eof
- msg_floppy db "The FLOPPY drives have been selected.",cr,lf,eof
- msg_stack db "The 8086 stack was not properly cleaned up on exit.",cr,lf,bell,eof
- msg_missing db "Missing Parameter. Command Ignored. ",cr,lf,eof
-
- msg_seektime db cr,lf,"Time to seek from zero to desired track: ",eof
- msg_recaltime db cr,lf,"Time to slow seek back to track zero: ",eof
-
- msg_min db " minutes, ",eof
- msg_sec db ".",eof
- msg_100ths db " seconds.",eof
-
- msg_drives db cr,lf,"Hard drives found: ",eof
- msg_sel db ", Drive Selected: ",eof
- msg_tracks db ", TRACKs: ",eof
- msg_heads db ", HEADs: ",eof
- msg_sectors db ", SECTORs: ",eof
- msg_crlf db cr,lf,eof
-
- msg_numtracks db "Number of tracks read: ",eof
- msg_readtime db ". Elapsed time: ",eof
-
- bad_msg db cr,lf,"Either the program or controller failed. Controller Error Code: ",bell,eof
-
- msg_help db cr,lf
- db "This program uses the slash commands shown below to determine the ",cr,lf
- db "performance of a hard disk drive or controller. If a /2 is detected ",cr,lf
- db "on the command line, then all testing is directed to the second drive. ",cr,lf
- db "The commands are listed in the order they will be executed. ",cr,lf,lf
-
- db " /2 Use the second drive instead of the first. ",cr,lf
- ; db " /F The Floppy drive is selected instead of hard disk. ",cr,lf
- db " /I INFOrmation about the drive is reported. ",cr,lf
- db " /S n SEEK test from 0 to 'n' and Recal from 'n' to 0. ",cr,lf
- db " /R n READ 'n' Tracks and report the time taken. ",cr,lf
- db " /P PARK the drive on the last track. ",cr,lf
- db " /? HELP screen displayed. ",cr,lf,eof
-
- Buffer dw 0 ;this is the start of the read buffer
-
- HD endp
- code_seg ends
- end entry
-
- ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
-
- On entry to the Hard Disk ROM Bios, AH is set with one of the
- following values, depending of the function requested:
- AH = 00 Reset the hard disk
- AH = 08 Get the drive parameters
- AH = 0Ch Seek to the desired track
-
- Additional registers which may have to be set on entry are:
- DH = 0..7 Head number
- DL = 80..87h Drive number where 80 = first hard drive
- CH = 0..1023 Low byte of Cylinder number
- CL = cc-sssss Sector number and high bits of Cylinder number
- AL = 1..80h Number of sectors (or interleave for format)
- ES:BX Address of buffer for reads and writes
-
- In the event of a failure, the AH returns the error code, and
- the carry bit is set. If no falilure, CY=0 and AH=0.
-
- If Drive Parameters are requested, they are returned as follows:
- DH = 0..h-1 Maximum head number
- DL = 1..2 Number of hard drives attached
- CH = 1..1023 Max useable cylinder number, low byte
- CL = cc-sssss Max useable sector number and hi bits of cyl
-